//希望是一个工具模块当中重写的以下方法
//希望在原型上拓展call/apply/bind方法
const utilsModule = (function (Function) {
  //外面注入的Function作为局部变量

  //ctx -> 执行期上下文
  //ctx 必须是一个引用值对象
  //说明只有函数(对象不行)才能调用myApply方法
  Function.prototype.myApply = function (ctx, args) {
    ctx = ctx ? Object(ctx) : window;
    ctx.originFn = this;

    //原始值 或 不是函数
    if (typeof args !== "object" && typeof args !== "function") {
      //情况1：
      //参数2写引用值会报错
      //参数2不是函数时会报错
      throw new TypeError("CreateListFromArrayLike called on non-object!");
    }

    //没传args 或 不是数组时
    if (!args || typeOf(args) !== "Array") {
      //情况2：参数2没写时直接执行没有参数的函数
      return ctx.originFn();
    }

    var ret = eval("ctx.originFn(" + args + ")");
    delete ctx.originFn;

    return ret;
  };

  //用于判断applay第二个参数类型的函数
  function typeOf(value) {
    if (value === null) {
      return "null";
    }

    //({}).toString.call(value) -> '[object Object]' -> 'Object'

    //包装类 或 对象，函数
    return typeof value === "object"
      ? {
          "[object Object]": "Object",
          "[object Array]": "Array",
          "[object Number]": "Number",
          "[object String]": "String",
          "[object Boolean]": "Boolean",
        }[{}.toString.call(value)]
      : typeof value;
  }
})(Function);

export default utilsModule;
